class SoundManager {
    readyinfo;

    multichannellength: number; // zero based, so three tracks
    audiomemorycachelimit: number;

    playingList; //currently playing tracks

    audioAvailable; //Memory Available
    audioCache; //Memory in Use

    audioDictionary;
    audioGroups;

    globalvolume: number;
    mute: boolean;

    constructor(isMute) {
        this.readyinfo = { current: 0, expected: 0 };

        this.multichannellength = 2; // zero based, so three tracks
        this.audiomemorycachelimit = 45;

        this.playingList = []; //currently playing tracks

        this.audioAvailable = []; //Memory Available
        this.audioCache = []; //Memory in Use

        this.audioDictionary = {};
        this.audioGroups = {};

        this.globalvolume = 0.2;
        this.mute = false;

        this.init(isMute);
    }

    init(isMute) {
        var that = this;
        var readycallback = function () {
            that.readytoplay(this.NAME);
        }

        var endedcallback = function () {
            that.soundendedplay(this.NAME);
        };

        var errorcallback = function (e) {
            that.sounderror(this.NAME, e);
        };

        for (var i = 0; i < this.audiomemorycachelimit; i++) {
            this.audioAvailable.push(i);
            this.audioCache[i] = new Audio("media/Sounds/atompop.mp3"); //just a generic file to get placed
            this.audioCache[i].preload = "none";
            this.audioCache[i].addEventListener('canplaythrough', readycallback, false);
            this.audioCache[i].addEventListener('ended', endedcallback, false);
            this.audioCache[i].addEventListener('error', errorcallback, false);
            this.audioCache[i].addEventListener('onerror', errorcallback, false);
            this.audioCache[i].PLAYING = false;
            this.audioCache[i].MULTICHANNEL = false;
            this.audioCache[i].ORIGINALVOLUME = 1.0;
        }

        if (isMute) {
            this.mute_all(false);
        }

    }

    //Called during level load to cache the sounds
    preloadsounds(group_name, sound_array) {
        this.audioGroups[group_name] = [];

        for (var i = 0; i < sound_array.length; i++) {
            this.audioGroups[group_name][i] = this.load(sound_array[i].name, sound_array[i].path, sound_array[i].loop, sound_array[i].multichannel);
        }
    }


    //String Key is name used in Dictionary for calling sounds, Path is media path 'media/Sounds/x.*'
    load(string_key, path, loop, multichannel, volume?) {

        if (this.audioAvailable.length > 0) {
            if (!this.audioDictionary[string_key]) {
                var currentAudio = this.audioCache[this.audioAvailable.pop()]; //Pop top one off the available list
                currentAudio.src = path; //Change src and load the new data
                currentAudio.load();

                currentAudio.NAME = string_key;

                if (loop) {
                    currentAudio.loop = true;
                }
                else { currentAudio.loop = false; }

                if (volume) {
                    currentAudio.ORIGINALVOLUME = volume * this.globalvolume; //stores for mute/unmute purposes
                } else {
                    currentAudio.ORIGINALVOLUME = 1 * this.globalvolume;
                }
                if (this.mute) {
                    currentAudio.volume = 0;
                }
                else {
                    currentAudio.volume = currentAudio.ORIGINALVOLUME;
                }

                this.audioDictionary[string_key] = currentAudio; //Add to dictionary for reference

                this.readyinfo.expected++; //keep track of audio files being loaded
                console.log("LOADING: " + string_key);
                if (multichannel) {
                    currentAudio.MULTICHANNEL = true;
                    for (var i = 0; i < this.multichannellength; i++) {
                        this.load(string_key + i, path, loop, false, volume);
                    }
                }
                else {
                    currentAudio.MULTICHANNEL = false;
                }
                return string_key;
            }
            else {
                return string_key;
                console.log("STRING KEY ALREADY EXISTS: " + string_key);
            }
        }
        else {
            console.log("AUDIO CACHE FULL: " + string_key);
        }
    }

    unload_group(group_name) {
        var group = this.audioGroups[group_name];
        if (group) {
            for (var i = 0; i < group.length; i++) {
                this.unload(group[i]);
            }

            delete this.audioGroups[group_name];

            return true;
        }
        return false;
    }

    unload(string_key) {

        var audiosample = this.audioDictionary[string_key];
        if (audiosample) {
            var index = this.audioCache.indexOf(audiosample);
            if (index >= 0) {
                this.audioAvailable.push(index); //push index to signal that the audio data is available for use
            }
            if (audiosample.MULTICHANNEL) {
                for (var i = 0; i < this.multichannellength; i++) {
                    this.unload(string_key + i);
                }
            }
            delete this.audioDictionary[string_key]; //remove string_key from dictionary
        }
    }

    play(string_key) {
        if (this.audioDictionary[string_key]) {
            var audiosample = this.audioDictionary[string_key];

            if (audiosample.PLAYING) {
                if (!audiosample.MULTICHANNEL) {
                    audiosample.currentTime = 0;
                }
                else {
                    var maxDuration = 0;
                    var maxplayedSample;
                    for (var i = 0; i < this.multichannellength; i++) {
                        audiosample = this.audioDictionary[string_key + i];
                        if (audiosample.PLAYING === false) {
                            audiosample.play();
                            audiosample.PLAYING = true;
                            return; //unused audio sample found, break out of loop
                        }
                        else {
                            if (maxDuration <= audiosample.currentTime) {
                                maxDuration = audiosample.currentTime;
                                maxplayedSample = audiosample; //set sample to sample with highest time
                            }
                        }
                    }

                    maxplayedSample.currentTime = 0; //if here no unused samples found, reset sample with highest duration
                }
            }
            else {
                audiosample.PLAYING = true;
                audiosample.play();
            }
        }
        else {
            console.log("SOUND NOT FOUND: " + string_key);
        }
    }

    readytoplay(string_key) {
        this.readyinfo.current++;
        this.readyinfo.expected--;
        this.readyinfo.expected = Math.max(0, this.readyinfo.expected);
    }

    soundendedplay(string_key) {
        this.audioDictionary[string_key].PLAYING = false;
    }

    sounderror(string_key, event) {

        console.log("AUDIO EVENT ERROR CODE: " + event.currentTarget.error.code);

        this.readyinfo.current++;
        this.readyinfo.expected--;
        this.readyinfo.expected = Math.max(0, this.readyinfo.expected);

    }

    stopall() {
        for (var i = 0; i < this.audioCache.length; i++) {
            this.audioCache[i].pause();
            if (this.audioCache[i].currentTime != 0) {
                this.audioCache[i].currentTime = 0;
            }
            this.audioCache[i].PLAYING = false;
        }
    }

    stop(string_key) {
        if (this.audioDictionary[string_key]) {
            var audiosample = this.audioDictionary[string_key];
            audiosample.PLAYING = false;
            audiosample.currentTime = 0;
            audiosample.pause();
        }
        else {
            console.log("STOPPING UNLOADED SOUND: " + string_key);
        }
    }

    mute_all(toggle) {
        if (!toggle) {
            for (var i = 0; i < this.audioCache.length; i++) {
                this.audioCache[i].volume = 0;
            }
            this.mute = true;
            return true;
        }
        else {
            for (var i = 0; i < this.audioCache.length; i++) {
                this.audioCache[i].volume = this.audioCache[i].ORIGINALVOLUME;
            }
            this.mute = false;
        }
        return false;
    }

    mute_toggle() {
        //return true if muted
        return this.mute_all(this.mute);
    }

} 